home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / nfs / nfswatch4.0 / dlpi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-01  |  11.5 KB  |  638 lines

  1. #ifndef lint
  2. static char *RCSid = "$Header: /home/harbor/davy/system/nfswatch/RCS/dlpi.c,v 4.0 1993/03/01 19:59:00 davy Exp $";
  3. #endif
  4.  
  5. #include "os.h"
  6.  
  7. #ifdef USE_DLPI
  8. /*
  9.  * dpli.c - routines for messing with the Data Link Provider Interface.
  10.  *
  11.  * The code in this module is based in large part (especially the dl*
  12.  * routines) on the example code provided with the document "How to Use
  13.  * DLPI", by Neal Nuckolls of Sun Internet Engineering.  Gotta give credit
  14.  * where credit is due.  If it weren't for Neal's excellent document,
  15.  * this module just plain wouldn't exist.
  16.  *
  17.  * David A. Curry
  18.  * Purdue University
  19.  * Engineering Computer Network
  20.  * 1285 Electrical Engineering Building
  21.  * West Lafayette, IN 47907-1285
  22.  * davy@ecn.purdue.edu
  23.  *
  24.  * $Log: dlpi.c,v $
  25.  * Revision 4.0  1993/03/01  19:59:00  davy
  26.  * NFSWATCH Version 4.0.
  27.  *
  28.  * Revision 1.5  1993/02/19  19:54:36  davy
  29.  * Another change in hopes of making things work on SVR4.
  30.  *
  31.  * Revision 1.4  1993/01/26  13:19:05  davy
  32.  * Fixed a goof in passing buffer size.
  33.  *
  34.  * Revision 1.3  1993/01/26  13:18:39  davy
  35.  * Added ifdef's to make it work on DLPI 1.3.
  36.  *
  37.  * Revision 1.2  1993/01/15  19:33:39  davy
  38.  * Miscellaneous cleanups.
  39.  *
  40.  * Revision 1.1  1993/01/15  15:42:32  davy
  41.  * Initial revision
  42.  *
  43.  */
  44. #include <sys/param.h>
  45. #include <sys/stropts.h>
  46. #include <sys/stream.h>
  47. #include <sys/dlpi.h>
  48. #ifdef SUNOS5
  49. #include <sys/bufmod.h>
  50. #endif
  51. #include <sys/socket.h>
  52. #include <sys/sockio.h>
  53. #include <sys/ioctl.h>
  54. #include <sys/time.h>
  55. #include <net/if.h>
  56. #include <signal.h>
  57. #include <string.h>
  58. #include <errno.h>
  59. #include <fcntl.h>
  60. #include <stdio.h>
  61.  
  62. #include "nfswatch.h"
  63. #include "externs.h"
  64.  
  65. static void    dlbindreq();
  66. static void    dlinforeq();
  67. static void    dlattachreq();
  68. static void    dlpromisconreq();
  69.  
  70. /*
  71.  * setup_dlpi_dev - set up the data link provider interface.
  72.  */
  73. int
  74. setup_dlpi_dev(device)
  75. char **device;
  76. {
  77.     char *p;
  78.     u_int chunksz;
  79.     char cbuf[BUFSIZ];
  80.     struct ifconf ifc;
  81.     struct ifreq *ifrp;
  82.     struct strioctl si;
  83.     char devname[BUFSIZ];
  84.     int n, s, fd, devppa;
  85.     struct timeval timeout;
  86.     long buf[DLPI_MAXDLBUF];
  87.  
  88.     /*
  89.      * If the interface device was not specified,
  90.      * get the default one.
  91.      */
  92.     if (*device == NULL) {
  93.         /*
  94.          * Grab a socket.
  95.          */
  96.         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  97.             error("socket");
  98.             finish(-1);
  99.         }
  100.  
  101.         ifc.ifc_buf = cbuf;
  102.         ifc.ifc_len = sizeof(cbuf);
  103.  
  104.         /*
  105.          * See what devices we've got.
  106.          */
  107.         if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
  108.             error("ioctl: SIOCGIFCONF");
  109.             finish(-1);
  110.         }
  111.  
  112.         /*
  113.          * Take the first device we encounter.
  114.          */
  115.         ifrp = ifc.ifc_req;
  116.         for (n = ifc.ifc_len/sizeof(struct ifreq); n > 0; n--,ifrp++) {
  117.             /*
  118.              * Skip the loopback interface.
  119.              */
  120.             if (strcmp(ifrp->ifr_name, "lo0") == 0)
  121.                 continue;
  122.  
  123.             *device = savestr(ifrp->ifr_name);
  124.             break;
  125.         }
  126.  
  127.         (void) close(s);
  128.     }
  129.  
  130.     /*
  131.      * Split the device name into type and unit number.
  132.      */
  133.     if ((p = strpbrk(*device, "0123456789")) == NULL)
  134.         return(-1);
  135.  
  136.     strcpy(devname, DLPI_DEVDIR);
  137.     strncat(devname, *device, p - *device);
  138.     devppa = atoi(p);
  139.  
  140.     /*
  141.      * Open the device.
  142.      */
  143.     if ((fd = open(devname, O_RDWR)) < 0) {
  144.         if (errno == ENOENT || errno == ENXIO)
  145.             return(-1);
  146.  
  147.         error(devname);
  148.         finish(-1);
  149.     }
  150.  
  151.     /*
  152.      * Attach to the device.  If this fails, the device
  153.      * does not exist.
  154.      */
  155.     dlattachreq(fd, devppa);
  156.  
  157.     if (dlokack(fd, buf) < 0) {
  158.         close(fd);
  159.         return(-1);
  160.     }
  161.  
  162.     /*
  163.      * We want the ethernet in promiscuous mode if we're looking
  164.      * at nodes other than ourselves.
  165.      */
  166.     if (allflag || dstflag) {
  167. #ifdef DL_PROMISC_PHYS
  168.         dlpromisconreq(fd, DL_PROMISC_PHYS);
  169.  
  170.         if (dlokack(fd, buf) < 0) {
  171.             fprintf(stderr, "%s: DL_PROMISC_PHYS failed.\n", pname);
  172.             finish(-1);
  173.         }
  174. #else
  175.         fprintf(stderr, "%s: DLPI 1.3 does not support promiscuous ",
  176.             pname);
  177.         fprintf(stderr, "mode operation.\n");
  178.         fprintf(stderr, "%s: cannot implement -all or -dst options.\n",
  179.             pname);
  180.         finish(-1);
  181. #endif
  182.     }
  183.  
  184.     /*
  185.      * Bind to the specific unit.
  186.      */
  187.     dlbindreq(fd, DLPI_DEFAULTSAP, 0, DL_CLDLS, 0, 0);
  188.  
  189.     if (dlbindack(fd, buf) < 0) {
  190.         fprintf(stderr, "%s: dlbindack failed.\n", pname);
  191.         finish(-1);
  192.     }
  193.  
  194. #ifdef SUNOS5
  195.     /*
  196.      * We really want all types of packets.  However, the SVR4 DLPI does
  197.      * not let you have the packet frame header, so we won't be able to
  198.      * distinguish protocol types.  But SunOS5 gives you the DLIOCRAW
  199.      * ioctl to get the frame headers, so we can do this on SunOS5.
  200.      */
  201.     dlpromisconreq(fd, DL_PROMISC_SAP);
  202.  
  203.     if (dlokack(fd, buf) < 0) {
  204.         fprintf(stderr, "%s: DL_PROMISC_SAP failed.\n", pname);
  205.         finish(-1);
  206.     }
  207.  
  208.     /*
  209.      * We want raw packets with the packet frame header.  But we can
  210.      * only get this in SunOS5 with the DLIOCRAW ioctl; it's not in
  211.      * standard SVR4.
  212.      */
  213.     si.ic_cmd = DLIOCRAW;
  214.     si.ic_timout = -1;
  215.     si.ic_len = 0;
  216.     si.ic_dp = 0;
  217.  
  218.     if (ioctl(fd, I_STR, &si) < 0) {
  219.         error("ioctl: I_STR DLIOCRAW");
  220.         finish(-1);
  221.     }
  222. #endif /* SUNOS5 */
  223.  
  224.     /*
  225.      * Arrange to get discrete messages.
  226.      */
  227.     if (ioctl(fd, I_SRDOPT, (char *) RMSGD) < 0) {
  228.         error("ioctl: I_SRDOPT RMSGD");
  229.         finish(-1);
  230.     }
  231.  
  232. #ifdef SUNOS5
  233.     /*
  234.      * Push and configure the streams buffering module.  This is once
  235.      * again SunOS-specific.
  236.      */
  237.     if (ioctl(fd, I_PUSH, DLPI_BUFMOD) < 0) {
  238.         error("ioctl: I_PUSH BUFMOD");
  239.         finish(-1);
  240.     }
  241.  
  242.     /*
  243.      * Set the read timeout.
  244.      */
  245.     timeout.tv_sec = 1;
  246.     timeout.tv_usec = 0;
  247.  
  248.     si.ic_cmd = SBIOCSTIME;
  249.     si.ic_timout = INFTIM;
  250.     si.ic_len = sizeof(timeout);
  251.     si.ic_dp = (char *) &timeout;
  252.  
  253.     if (ioctl(fd, I_STR, (char *) &si) < 0) {
  254.         error("ioctl: I_STR SBIOCSTIME");
  255.         finish(-1);
  256.     }
  257.  
  258.     /*
  259.      * Set the chunk size.
  260.      */
  261.     chunksz = DLPI_CHUNKSIZE;
  262.  
  263.     si.ic_cmd = SBIOCSCHUNK;
  264.     si.ic_len = sizeof(chunksz);
  265.     si.ic_dp = (char *) &chunksz;
  266.  
  267.     if (ioctl(fd, I_STR, (char *) &si) < 0) {
  268.         error("ioctl: I_STR SBIOCSCHUNK");
  269.         finish(-1);
  270.     }
  271.  
  272.     /*
  273.      * Set snapshot mode.
  274.      */
  275.     si.ic_cmd = SBIOCSSNAP;
  276.     si.ic_len = sizeof(truncation);
  277.     si.ic_dp = (char *) &truncation;
  278.  
  279.     if (ioctl(fd, I_STR, (char *) &si) < 0) {
  280.         error("ioctl: I_STR SBIOCSSNAP");
  281.         finish(-1);
  282.     }
  283. #endif /* SUNOS5 */
  284.  
  285.     return(fd);
  286. }
  287.  
  288. /*
  289.  * flush_dlpi - flush data from the dlpi.
  290.  */
  291. void
  292. flush_dlpi(fd)
  293. int fd;
  294. {
  295.     if (ioctl(fd, I_FLUSH, (char *) FLUSHR) < 0) {
  296.         error("ioctl: I_FLUSH");
  297.         finish(-1);
  298.     }
  299. }
  300.  
  301. /*
  302.  * dlpi_devtype - determine the type of device we're looking at.
  303.  */
  304. int
  305. dlpi_devtype(fd)
  306. int fd;
  307. {
  308.     long buf[DLPI_MAXDLBUF];
  309.     union DL_primitives *dlp;
  310.  
  311.     dlp = (union DL_primitives *) buf;
  312.  
  313.     dlinforeq(fd);
  314.  
  315.     if (dlinfoack(fd, buf) < 0)
  316.         return(DLT_EN10MB);
  317.  
  318.     switch (dlp->info_ack.dl_mac_type) {
  319.     case DL_CSMACD:
  320.     case DL_ETHER:
  321.         return(DLT_EN10MB);
  322. #ifdef DL_FDDI
  323.     case DL_FDDI:
  324.         return(DLT_FDDI);
  325. #endif
  326.     default:
  327.         fprintf(stderr, "%s: DLPI MACtype %d unknown, ", pname,
  328.             dlp->info_ack.dl_mac_type);
  329.         fprintf(stderr, "assuming ethernet.\n");
  330.         return(DLT_EN10MB);
  331.     }
  332. }
  333.  
  334. /*
  335.  * dlinforeq - request information about the data link provider.
  336.  */
  337. static void
  338. dlinforeq(fd)
  339. int fd;
  340. {
  341.     dl_info_req_t info_req;
  342.     struct strbuf ctl;
  343.     int flags;
  344.  
  345.     info_req.dl_primitive = DL_INFO_REQ;
  346.  
  347.     ctl.maxlen = 0;
  348.     ctl.len = sizeof (info_req);
  349.     ctl.buf = (char *) &info_req;
  350.  
  351.     flags = RS_HIPRI;
  352.  
  353.     if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
  354.         error("putmsg");
  355.         finish(-1);
  356.     }
  357. }
  358.  
  359. /*
  360.  * dlattachreq - send a request to attach.
  361.  */
  362. static void
  363. dlattachreq(fd, ppa)
  364. u_long ppa;
  365. int fd;
  366. {
  367.     dl_attach_req_t    attach_req;
  368.     struct strbuf ctl;
  369.     int flags;
  370.  
  371.     attach_req.dl_primitive = DL_ATTACH_REQ;
  372.     attach_req.dl_ppa = ppa;
  373.  
  374.     ctl.maxlen = 0;
  375.     ctl.len = sizeof (attach_req);
  376.     ctl.buf = (char *) &attach_req;
  377.  
  378.     flags = 0;
  379.  
  380.     if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) {
  381.         error("putmsg");
  382.         finish(-1);
  383.     }
  384. }
  385.  
  386. #ifdef DL_PROMISCON_REQ
  387. /*
  388.  * dlpromisconreq - send a request to turn promiscuous mode on.
  389.  */
  390. static void
  391. dlpromisconreq(fd, level)
  392. u_long level;
  393. int fd;
  394. {
  395.     dl_promiscon_req_t promiscon_req;
  396.     struct strbuf ctl;
  397.     int flags;
  398.  
  399.     promiscon_req.dl_primitive = DL_PROMISCON_REQ;
  400.     promiscon_req.dl_level = level;
  401.  
  402.     ctl.maxlen = 0;
  403.     ctl.len = sizeof (promiscon_req);
  404.     ctl.buf = (char *) &promiscon_req;
  405.  
  406.     flags = 0;
  407.  
  408.     if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) {
  409.         error("putmsg");
  410.         finish(-1);
  411.     }
  412. }
  413. #endif /* DL_PROMISCON_REQ */
  414.  
  415. /*
  416.  * dlbindreq - send a request to bind.
  417.  */
  418. static void
  419. dlbindreq(fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
  420. u_long sap, max_conind, service_mode, conn_mgmt, xidtest;
  421. int fd;
  422. {
  423.     dl_bind_req_t bind_req;
  424.     struct strbuf ctl;
  425.     int flags;
  426.  
  427.     bind_req.dl_primitive = DL_BIND_REQ;
  428.     bind_req.dl_sap = sap;
  429.     bind_req.dl_max_conind = max_conind;
  430.     bind_req.dl_service_mode = service_mode;
  431.     bind_req.dl_conn_mgmt = conn_mgmt;
  432. #ifdef DL_PROMISC_PHYS
  433.     /*
  434.      * DLPI 2.0 only?
  435.      */
  436.     bind_req.dl_xidtest_flg = xidtest;
  437. #endif
  438.  
  439.     ctl.maxlen = 0;
  440.     ctl.len = sizeof (bind_req);
  441.     ctl.buf = (char *) &bind_req;
  442.  
  443.     flags = 0;
  444.  
  445.     if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) {
  446.         error("putmsg");
  447.         finish(-1);
  448.     }
  449. }
  450.  
  451. /*
  452.  * dlokack - general acknowledgement reception.
  453.  */
  454. static int
  455. dlokack(fd, bufp)
  456. char *bufp;
  457. int fd;
  458. {
  459.     union DL_primitives *dlp;
  460.     struct strbuf ctl;
  461.     int flags;
  462.  
  463.     ctl.maxlen = DLPI_MAXDLBUF;
  464.     ctl.len = 0;
  465.     ctl.buf = bufp;
  466.  
  467.     if (strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack") < 0)
  468.         return(-1);
  469.  
  470.     dlp = (union DL_primitives *) ctl.buf;
  471.  
  472.     if (expecting(DL_OK_ACK, dlp) < 0)
  473.         return(-1);
  474.  
  475.     if (ctl.len < sizeof (dl_ok_ack_t))
  476.         return(-1);
  477.  
  478.     if (flags != RS_HIPRI)
  479.         return(-1);
  480.  
  481.     if (ctl.len < sizeof (dl_ok_ack_t))
  482.         return(-1);
  483.  
  484.     return(0);
  485. }
  486.  
  487. /*
  488.  * dlinfoack - receive an ack to a dlinforeq.
  489.  */
  490. static int
  491. dlinfoack(fd, bufp)
  492. char *bufp;
  493. int fd;
  494. {
  495.     union DL_primitives *dlp;
  496.     struct strbuf ctl;
  497.     int flags;
  498.  
  499.     ctl.maxlen = DLPI_MAXDLBUF;
  500.     ctl.len = 0;
  501.     ctl.buf = bufp;
  502.  
  503.     if (strgetmsg(fd, &ctl, (struct strbuf *)NULL, &flags, "dlinfoack") < 0)
  504.         return(-1);
  505.  
  506.     dlp = (union DL_primitives *) ctl.buf;
  507.  
  508.     if (expecting(DL_INFO_ACK, dlp) < 0)
  509.         return(-1);
  510.  
  511.     if (ctl.len < sizeof (dl_info_ack_t))
  512.         return(-1);
  513.  
  514.     if (flags != RS_HIPRI)
  515.         return(-1);
  516.  
  517.     if (ctl.len < sizeof (dl_info_ack_t))
  518.         return(-1);
  519.  
  520.     return(0);
  521. }
  522.  
  523. /*
  524.  * dlbindack - receive an ack to a dlbindreq.
  525.  */
  526. static int
  527. dlbindack(fd, bufp)
  528. char *bufp;
  529. int fd;
  530. {
  531.     union DL_primitives *dlp;
  532.     struct strbuf ctl;
  533.     int flags;
  534.  
  535.     ctl.maxlen = DLPI_MAXDLBUF;
  536.     ctl.len = 0;
  537.     ctl.buf = bufp;
  538.  
  539.     if (strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack") < 0)
  540.         return(-1);
  541.  
  542.     dlp = (union DL_primitives *) ctl.buf;
  543.  
  544.     if (expecting(DL_BIND_ACK, dlp) < 0)
  545.         return(-1);
  546.  
  547.     if (flags != RS_HIPRI)
  548.         return(-1);
  549.  
  550.     if (ctl.len < sizeof (dl_bind_ack_t))
  551.         return(-1);
  552.  
  553.     return(0);
  554. }
  555.  
  556. /*
  557.  * expecting - see if we got what we wanted.
  558.  */
  559. static int
  560. expecting(prim, dlp)
  561. union DL_primitives *dlp;
  562. int prim;
  563. {
  564.     if (dlp->dl_primitive != (u_long)prim)
  565.         return(-1);
  566.  
  567.     return(0);
  568. }
  569.  
  570. /*
  571.  * strgetmsg - get a message from a stream, with timeout.
  572.  */
  573. static int
  574. strgetmsg(fd, ctlp, datap, flagsp, caller)
  575. struct strbuf *ctlp, *datap;
  576. char *caller;
  577. int *flagsp;
  578. int fd;
  579. {
  580.     int rc;
  581.     void sigalrm();
  582.  
  583.     /*
  584.      * Start timer.
  585.      */
  586.     (void) sigset(SIGALRM, sigalrm);
  587.  
  588.     if (alarm(DLPI_MAXWAIT) < 0) {
  589.         error("alarm");
  590.         finish(-1);
  591.     }
  592.  
  593.     /*
  594.      * Set flags argument and issue getmsg().
  595.      */
  596.     *flagsp = 0;
  597.     if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
  598.         error("getmsg");
  599.         finish(-1);
  600.     }
  601.  
  602.     /*
  603.      * Stop timer.
  604.      */
  605.     if (alarm(0) < 0) {
  606.         error("alarm");
  607.         finish(-1);
  608.     }
  609.  
  610.     /*
  611.      * Check for MOREDATA and/or MORECTL.
  612.      */
  613.     if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA))
  614.         return(-1);
  615.     if (rc & MORECTL)
  616.         return(-1);
  617.     if (rc & MOREDATA)
  618.         return(-1);
  619.  
  620.     /*
  621.      * Check for at least sizeof (long) control data portion.
  622.      */
  623.     if (ctlp->len < sizeof (long))
  624.         return(-1);
  625.  
  626.     return(0);
  627. }
  628.  
  629. /*
  630.  * sigalrm - handle alarms.
  631.  */
  632. static void
  633. sigalrm()
  634. {
  635.     (void) fprintf(stderr, "dlpi: timeout\n");
  636. }
  637. #endif /* USE_DLPI */
  638.